<template><div><p>本文档最新版为 <a href="https://learnku.com/docs/laravel/10.x" target="_blank" rel="noopener noreferrer">10.x</a>，旧版本可能放弃维护，推荐阅读最新版！</p>
<h2 id="laravel-cashier" tabindex="-1"><a class="header-anchor" href="#laravel-cashier"><span>Laravel Cashier</span></a></h2>
<ul>
<li><a href="#introduction">简介</a></li>
<li><a href="#upgrading-cashier">升级 Cashier</a></li>
<li><a href="#installation">安装</a></li>
<li><a href="#configuration">配置</a>
<ul>
<li><a href="#billable-model">Billable 模型</a></li>
<li><a href="#api-keys">API Keys</a></li>
<li><a href="#currency-configuration">货币配置</a></li>
</ul>
</li>
<li><a href="#customers">客户</a>
<ul>
<li><a href="#creating-customers">创建客户</a></li>
</ul>
</li>
<li><a href="#payment-methods">支付方式</a>
<ul>
<li><a href="#storing-payment-methods">存储支付方式</a></li>
<li><a href="#retrieving-payment-methods">获取支付方式</a></li>
<li><a href="#check-for-a-payment-method">确认用户是否拥有支付方式</a></li>
<li><a href="#updating-the-default-payment-method">更新默认支付方式</a></li>
<li><a href="#adding-payment-methods">添加支付方式</a></li>
<li><a href="#deleting-payment-methods">删除支付方式</a></li>
</ul>
</li>
<li><a href="#subscriptions">订阅</a>
<ul>
<li><a href="#creating-subscriptions">创建订阅</a></li>
<li><a href="#checking-subscription-status">检查订阅状态</a></li>
<li><a href="#changing-plans">修改订阅计划</a></li>
<li><a href="#subscription-quantity">订阅量</a></li>
<li><a href="#subscription-taxes">订阅税额</a></li>
<li><a href="#subscription-anchor-date">订阅锚定日期</a></li>
<li><a href="#cancelling-subscriptions">取消订阅</a></li>
<li><a href="#resuming-subscriptions">恢复订阅</a></li>
</ul>
</li>
<li><a href="#subscription-trials">订阅试用</a>
<ul>
<li><a href="#with-payment-method-up-front">预付款方式</a></li>
<li><a href="#without-payment-method-up-front">非预付款方式</a></li>
</ul>
</li>
<li><a href="#handling-stripe-webhooks">处理 Stripe Webhooks</a>
<ul>
<li><a href="#defining-webhook-event-handlers">定义 Webhook 事件句柄</a></li>
<li><a href="#handling-failed-subscriptions">订阅失败</a></li>
<li><a href="#verifying-webhook-signatures">验证 Webhook 签名</a></li>
</ul>
</li>
<li><a href="#single-charges">一次性支付</a>
<ul>
<li><a href="#simple-charge">简单支付</a></li>
<li><a href="#charge-with-invoice">费用与发票</a></li>
<li><a href="#refunding-charges">关于退款</a></li>
</ul>
</li>
<li><a href="#invoices">发票</a>
<ul>
<li><a href="#generating-invoice-pdfs">生成电子发票</a></li>
</ul>
</li>
<li><a href="#strong-customer-authentication">强客户身份验证 (SCA)</a>
<ul>
<li><a href="#payments-requiring-additional-confirmation">需求额外验证的支付</a></li>
<li><a href="#off-session-payment-notifications">无会话(Off-session) 支付通知</a></li>
</ul>
</li>
</ul>
<h2 id="简介" tabindex="-1"><a class="header-anchor" href="#简介"><span>简介</span></a></h2>
<p>Laravel Cashier 提供了直观而流畅的接口来接入 <a href="https://stripe.com/" target="_blank" rel="noopener noreferrer">Stripe</a> 付费订阅服务，它可以处理几乎所有的让你头疼的付费订阅代码。除了基本的订阅管理之外，Cashier 还可以帮你处理优惠券、交换订阅、订阅数量、取消宽限期，甚至还可以生成 PDF 电子发票。</p>
<blockquote>
<p>{注意} 为防止破坏性的更改，Cashier 使用固定的 Stripe API 版本。Cashier 10.1 利用 Stripe API <code v-pre>2019-08-14</code> 版本。Stripe API 版本将在次要分发上更新以便使用新的 Stripe 特性和改进。</p>
</blockquote>
<h2 id="升级-cashier" tabindex="-1"><a class="header-anchor" href="#升级-cashier"><span>升级 Cashier</span></a></h2>
<p>当你升级到新版本 Cashier 时，,请务必仔细阅读 <a href="https://github.com/laravel/cashier/blob/master/UPGRADE.md" target="_blank" rel="noopener noreferrer">Cashier 升级指南</a>。</p>
<h2 id="安装" tabindex="-1"><a class="header-anchor" href="#安装"><span>安装</span></a></h2>
<p>首先，使用 composer 将 Stripe 的 Cashier 包添加到项目依赖中：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">composer <span class="token keyword">require</span> laravel<span class="token operator">/</span>cashier</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>{注意} 为确保 Cashier 正确的处理所有的 Stripe 事件，请记得 <a href="#handling-stripe-webhooks">配置 Cashier webhook 处理</a>。</p>
</blockquote>
<h4 id="数据库迁移" tabindex="-1"><a class="header-anchor" href="#数据库迁移"><span>数据库迁移</span></a></h4>
<p>Cashier 服务提供者注册了自己的数据库迁移目录，请记住在安装完包后迁移你的数据库。Cashier 迁移会在你的 <code v-pre>users</code> 表中增加几列并创建一个新的 <code v-pre>subscriptions</code> 表来保存你所有客户的订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">php artisan migrate</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果你需要覆盖 Cashier 包附带的迁移，可以使用 <code v-pre>vendor:publish</code> Artisan 命令发布它们:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">php artisan vendor<span class="token punctuation">:</span>publish <span class="token operator">--</span>tag<span class="token operator">=</span><span class="token string double-quoted-string">"cashier-migrations"</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果你想阻止 Cashier 迁移完全运行，可以使用 Cashier 提供的 <code v-pre>ignoreMigrations</code> 。通常，你应该在 <code v-pre>AppServiceProvider</code> 的 <code v-pre>register</code> 方法中调用这个方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Cashier</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Cashier</span><span class="token operator">::</span><span class="token function">ignoreMigrations</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>{注意} Stripe 建议用来存储 stripe 标识符的所有列应该大小写敏感。因此，以 MySQL 数据库为例，你应该确保 <code v-pre>stripe_id</code> 列的列排序规则设置为 <code v-pre>utf8_bin</code> ，更多信息可以在 <a href="https://stripe.com/docs/upgrades#what-changes-does-stripe-consider-to-be-backwards-compatible" target="_blank" rel="noopener noreferrer">Stripe 文档</a> 中找到。</p>
</blockquote>
<h2 id="配置" tabindex="-1"><a class="header-anchor" href="#配置"><span>配置</span></a></h2>
<h3 id="billable-模型" tabindex="-1"><a class="header-anchor" href="#billable-模型"><span>Billable 模型</span></a></h3>
<p>在使用 Cashier 之前， 添加 <code v-pre>Billable</code> Trait 到你的模型定义中。 这个 Trait 提供了多种方法以便你执行常见的支付任务，如创建订阅、申请优惠券以及更新支付方式信息：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Billable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">Billable</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Cashier 暂定你的 Billable 模型是 Laravel 附带的 <code v-pre>App\User</code> 类，如果你想修改请在你的 <code v-pre>.env</code> 文件中指定一个不同的模型：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token constant">CASHIER_MODEL</span><span class="token operator">=</span>App\User</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>{注意} 如果你使用的不是 Laravel 提供的 <code v-pre>App\User</code> 模型，你应该发布并更改提供的 <a href="#installation">migrations</a> 以匹配你的代替模型数据表名。</p>
</blockquote>
<h3 id="api-密钥" tabindex="-1"><a class="header-anchor" href="#api-密钥"><span>API 密钥</span></a></h3>
<p>接下来，您需要在 <code v-pre>.env</code> 中配置您的 Stripe 密钥。您可以在 Stripe 的控制面板中获取 Stripe API 密钥.</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token constant">STRIPE_KEY</span><span class="token operator">=</span>your<span class="token operator">-</span>stripe<span class="token operator">-</span>key</span>
<span class="line"><span class="token constant">STRIPE_SECRET</span><span class="token operator">=</span>your<span class="token operator">-</span>stripe<span class="token operator">-</span>secret</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="货币配置" tabindex="-1"><a class="header-anchor" href="#货币配置"><span>货币配置</span></a></h3>
<p>Cashier 的默认货币是美元 (USD)。您可以设置 <code v-pre>CASHIER_CURRENCY</code> 来更改默认的货币：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token constant">CASHIER_CURRENCY</span><span class="token operator">=</span>eur</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>为了配置 Cashier 使用的货币，您也许需要指定一个额外的 Locale（本地化） 参数，用于格式化在账单上面显示的金额。Cashier 内部使用 <a href="https://www.php.net/manual/en/class.numberformatter.php" target="_blank" rel="noopener noreferrer">PHP 的 <code v-pre>NumberFormatter</code> 类</a> 来格式化数字：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token constant">CASHIER_CURRENCY_LOCALE</span><span class="token operator">=</span>nl_BE</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>注意：要使用除了 <code v-pre>en</code> 之外的 Locale，确保 <code v-pre>ext-intl</code> 扩展在服务器上安装并配置好。</p>
</blockquote>
<h2 id="客户" tabindex="-1"><a class="header-anchor" href="#客户"><span>客户</span></a></h2>
<h3 id="创建客户" tabindex="-1"><a class="header-anchor" href="#创建客户"><span>创建客户</span></a></h3>
<p>有时，您可能希望在未订阅的情况下创建 Stripe 客户。您可以使用 <code v-pre>createAsStripeCustomer</code> 方法完成此操作：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createAsStripeCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>一旦在 Stripe 中创建了客户，您可以稍后便可开始订阅。</p>
<h2 id="支付方式" tabindex="-1"><a class="header-anchor" href="#支付方式"><span>支付方式</span></a></h2>
<h3 id="储存支付方式" tabindex="-1"><a class="header-anchor" href="#储存支付方式"><span>储存支付方式</span></a></h3>
<p>为了使用 Stripe 创建订阅或是一次性扣费，您将需要从 Stripe 获取支付方式并储存他的识别码。基于您计划使用的支付方式是用来一次性扣费还是订阅，我们有两种方案来达成，接下来我们一起来看一下这两种方法。</p>
<h4 id="用于订阅制的支付方法" tabindex="-1"><a class="header-anchor" href="#用于订阅制的支付方法"><span>用于订阅制的支付方法</span></a></h4>
<p>为了储存用户的信用卡供以后使用，Stripe 的 “Setup Intent” API 需要安全的获取用户的信用卡信息。“Setup Intent” 指示 Stripe 用户支付方式的意象。Cashier 的<code v-pre>Blillable</code> trait 包含了 <code v-pre>createSetupIntent</code> 方法来快速创建一个 “Setup Intent”。<br>
您应该在路由或者控制器调用这个方法来获取用户的支付方式意象：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-payment-method'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'intent'</span> <span class="token operator">=></span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createSetupIntent</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当您创建完 “Setup Intent” 并传递给视图后，您应该将它的密钥元素附加到获取用户支付信息的表单中。如下面这个“更新支付方式”表单：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token operator">&lt;</span>input id<span class="token operator">=</span><span class="token string double-quoted-string">"card-holder-name"</span> type<span class="token operator">=</span><span class="token string double-quoted-string">"text"</span><span class="token operator">></span></span>
<span class="line"></span>
<span class="line"><span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> Stripe Elements Placeholder <span class="token operator">--</span><span class="token operator">></span></span>
<span class="line"><span class="token operator">&lt;</span>div id<span class="token operator">=</span><span class="token string double-quoted-string">"card-element"</span><span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span></span>
<span class="line"></span>
<span class="line"><span class="token operator">&lt;</span>button id<span class="token operator">=</span><span class="token string double-quoted-string">"card-button"</span> data<span class="token operator">-</span>secret<span class="token operator">=</span><span class="token string double-quoted-string">"{{ <span class="token interpolation"><span class="token variable">$intent</span><span class="token operator">-></span><span class="token property">client_secret</span></span> }}"</span><span class="token operator">></span></span>
<span class="line">    Update Payment Method</span>
<span class="line"><span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>接下来，Stripe.js 库会调用这个密钥并安全地抓取用户的支付信息：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token operator">&lt;</span>script src<span class="token operator">=</span><span class="token string double-quoted-string">"https://js.stripe.com/v3/"</span><span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span></span>
<span class="line"></span>
<span class="line"><span class="token operator">&lt;</span>script<span class="token operator">></span></span>
<span class="line">    <span class="token keyword">const</span> <span class="token constant">stripe</span> <span class="token operator">=</span> <span class="token function">Stripe</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'stripe-public-key'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">const</span> <span class="token constant">elements</span> <span class="token operator">=</span> stripe<span class="token operator">.</span><span class="token function">elements</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token keyword">const</span> <span class="token constant">cardElement</span> <span class="token operator">=</span> elements<span class="token operator">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'card'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    cardElement<span class="token operator">.</span><span class="token function">mount</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'#card-element'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然后，卡片会被校验且您可以使用 [Stripe 的 <code v-pre>handleCardSetup</code> 方法] (<a href="https://stripe.com/docs/stripe-js/reference#stripe-handle-card-setup" target="_blank" rel="noopener noreferrer">stripe.com/docs/stripe-js/referenc...</a>%E6%9D%A5%E8%8E%B7%E5%8F%96%E4%B8%80%E4%B8%AA%E5%AE%89%E5%85%A8%E7%9A%84%E2%80%9C%E6%94%AF%E4%BB%98%E6%96%B9%E5%BC%8F%E8%AF%86%E5%88%AB%E7%A0%81)”：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">const</span> cardHolderName <span class="token operator">=</span> document<span class="token operator">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'card-holder-name'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">const</span> <span class="token constant">cardButton</span> <span class="token operator">=</span> document<span class="token operator">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'card-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">const</span> <span class="token constant">clientSecret</span> <span class="token operator">=</span> cardButton<span class="token operator">.</span>dataset<span class="token operator">.</span>secret<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">cardButton<span class="token operator">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'click'</span><span class="token punctuation">,</span> <span class="token function">async</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">const</span> <span class="token punctuation">{</span> setupIntent<span class="token punctuation">,</span> error <span class="token punctuation">}</span> <span class="token operator">=</span> await stripe<span class="token operator">.</span><span class="token function">handleCardSetup</span><span class="token punctuation">(</span></span>
<span class="line">        clientSecret<span class="token punctuation">,</span> cardElement<span class="token punctuation">,</span> <span class="token punctuation">{</span></span>
<span class="line">            payment_method_data<span class="token punctuation">:</span> <span class="token punctuation">{</span></span>
<span class="line">                billing_details<span class="token punctuation">:</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> cardHolderName<span class="token operator">.</span>value <span class="token punctuation">}</span></span>
<span class="line">            <span class="token punctuation">}</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 显示错误信息</span></span>
<span class="line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 卡片已成功验证</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当 Stripe 完成对客户支付方式的校验后，您可以将<code v-pre>setupIntent.payment_method</code> 识别码返回给您的应用并附加给客户。这次支付使用的支付方式可 <a href="#adding-payment-methods">被添加为新的支付方式</a> 或者 <a href="#updating-the-default-payment-method">用于更新默认支付方式</a>。您可以立即使用这个识别码来 <a href="#creating-subscriptions">创建一个订阅</a>.</p>
<blockquote>
<p>Tip：如果您希望了解更多有关 “Setup Intent” 与获取收集用户支付详情的信息，请参阅 <a href="https://stripe.com/docs/payments/cards/saving-cards#saving-card-without-payment" target="_blank" rel="noopener noreferrer">Stripe 的文档</a>.</p>
</blockquote>
<h4 id="用于一次性收费的支付方式" tabindex="-1"><a class="header-anchor" href="#用于一次性收费的支付方式"><span>用于一次性收费的支付方式</span></a></h4>
<p>当然，用于一次性收费的支付识别码我们只需要使用一次。由于 Stripe 的限制，您无法使用客户的一次性收费的支付方式。您需要用 Stripe.js 库来让客户填写他们的支付详情。让我们来看一下下面这个支付表单：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token operator">&lt;</span>input id<span class="token operator">=</span><span class="token string double-quoted-string">"card-holder-name"</span> type<span class="token operator">=</span><span class="token string double-quoted-string">"text"</span><span class="token operator">></span></span>
<span class="line"></span>
<span class="line"><span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> Stripe Elements Placeholder <span class="token operator">--</span><span class="token operator">></span></span>
<span class="line"><span class="token operator">&lt;</span>div id<span class="token operator">=</span><span class="token string double-quoted-string">"card-element"</span><span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span></span>
<span class="line"></span>
<span class="line"><span class="token operator">&lt;</span>button id<span class="token operator">=</span><span class="token string double-quoted-string">"card-button"</span><span class="token operator">></span></span>
<span class="line">    处理支付流程</span>
<span class="line"><span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>接下来，Stripe.js 可用来附加一个 Stripe 元素用于加密用户的支付方式详情：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token operator">&lt;</span>script src<span class="token operator">=</span><span class="token string double-quoted-string">"https://js.stripe.com/v3/"</span><span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span></span>
<span class="line"></span>
<span class="line"><span class="token operator">&lt;</span>script<span class="token operator">></span></span>
<span class="line">    <span class="token keyword">const</span> <span class="token constant">stripe</span> <span class="token operator">=</span> <span class="token function">Stripe</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'stripe-public-key'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">const</span> <span class="token constant">elements</span> <span class="token operator">=</span> stripe<span class="token operator">.</span><span class="token function">elements</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token keyword">const</span> <span class="token constant">cardElement</span> <span class="token operator">=</span> elements<span class="token operator">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'card'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    cardElement<span class="token operator">.</span><span class="token function">mount</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'#card-element'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然后，卡片会被校验且您可以使用 <a href="https://stripe.com/docs/stripe-js/reference#stripe-create-payment-method" target="_blank" rel="noopener noreferrer">Stripe 的 <code v-pre>createPaymentMethod</code>...</a>: 来获取一个安全的“支付方式识别码”：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">const</span> cardHolderName <span class="token operator">=</span> document<span class="token operator">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'card-holder-name'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">const</span> <span class="token constant">cardButton</span> <span class="token operator">=</span> document<span class="token operator">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'card-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">cardButton<span class="token operator">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'click'</span><span class="token punctuation">,</span> <span class="token function">async</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">const</span> <span class="token punctuation">{</span> paymentMethod<span class="token punctuation">,</span> error <span class="token punctuation">}</span> <span class="token operator">=</span> await stripe<span class="token operator">.</span><span class="token function">createPaymentMethod</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token string single-quoted-string">'card'</span><span class="token punctuation">,</span> cardElement<span class="token punctuation">,</span> <span class="token punctuation">{</span></span>
<span class="line">            billing_details<span class="token punctuation">:</span> <span class="token punctuation">{</span> name<span class="token punctuation">:</span> cardHolderName<span class="token operator">.</span>value <span class="token punctuation">}</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 错误信息</span></span>
<span class="line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 卡片验证成功</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果卡片验证成功，您可以将 <code v-pre>paymentMethod.id</code> 传递给您的应用并进行 <a href="#simple-charge">一次性付费</a>.</p>
<h3 id="获取支付方式" tabindex="-1"><a class="header-anchor" href="#获取支付方式"><span>获取支付方式</span></a></h3>
<p><code v-pre>Billable</code> 模块实例上的 <code v-pre>paymentMethods</code> 方法将返回一组 <code v-pre>Laravel\Cashier\PaymentMethod</code> 实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$paymentMethods</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">paymentMethods</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要获取默认的支付方式，可以使用 <code v-pre>defaultPaymentMethod</code>方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$paymentMethod</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">defaultPaymentMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="确认用户是否拥有支付方式" tabindex="-1"><a class="header-anchor" href="#确认用户是否拥有支付方式"><span>确认用户是否拥有支付方式</span></a></h3>
<p>要确认一个<code v-pre>Billable</code> 模型是否拥有一个支付方式，使用 <code v-pre>hasPaymentMethod</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">hasPaymentMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="更新默认的支付方式" tabindex="-1"><a class="header-anchor" href="#更新默认的支付方式"><span>更新默认的支付方式</span></a></h3>
<p><code v-pre>updateDefaultPaymentMethod</code> 可用来更新用户的默认支付方式。这个方法接受 Stripe 的支付方式识别码并且会将新分配的识别码设为默认的支付方式：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">updateDefaultPaymentMethod</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要在 Stripe 内同步您与客户的默认支付方式，您可以使用<br>
<code v-pre>updateDefaultPaymentMethodFromStripe</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">updateDefaultPaymentMethodFromStripe</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>注意：客户的默认支付方式只能用户创建发票或订阅，由于 Stripe 的限制，某些支付方式不适用于一次性收费</p>
</blockquote>
<h3 id="添加支付方式" tabindex="-1"><a class="header-anchor" href="#添加支付方式"><span>添加支付方式</span></a></h3>
<p>要添加新的支付方式，您可以在（可收费的） <code v-pre>Billable</code> 用户上调用 <code v-pre>addPaymentMethod</code> 方法，并传递支付方式识别码：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">addPaymentMethod</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>Tip：要学习如何获取并储存支付方式识别码，请参阅 <a href="#storing-payment-methods">支付方式储存</a>.</p>
</blockquote>
<h3 id="删除支付方式" tabindex="-1"><a class="header-anchor" href="#删除支付方式"><span>删除支付方式</span></a></h3>
<p>要删除一个支付方式，你可以调用 <code v-pre>Laravel\Cashier\PaymentMethod</code> 上的 <code v-pre>delete</code> 方法进行删除：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$paymentMethod</span><span class="token operator">-></span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>deletePaymentMethods</code> 方法将删除Billable模型的所有相关付款方式的信息：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">deletePaymentMethods</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>注意：如果用户的订阅比较活跃，那么应该阻止他们删除默认的付款方式。</p>
</blockquote>
<h2 id="订阅" tabindex="-1"><a class="header-anchor" href="#订阅"><span>订阅</span></a></h2>
<h3 id="创建订阅" tabindex="-1"><a class="header-anchor" href="#创建订阅"><span>创建订阅</span></a></h3>
<p>创建订阅，首先需要获取到一个 Billable 模型实例，这通常是 <code v-pre>App\User</code> 的一个实例。一旦您获取了模型实例，您可以使用 <code v-pre>newSubscription</code> 方法创建模型的订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'premium'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>newSubscription</code> 方法的第一个参数应该是订阅的名称。如果您的应用程序只提供一个订阅，那么您可以将其设置为 <code v-pre>main</code> or <code v-pre>primary</code>。第二个参数是用户订阅的 Stripe 计划。这个值应该与 Stripe 或 Braintree 中的标识符对应。</p>
<p><code v-pre>create</code> 方法接受一个 <a href="#storing-payment-methods">支付方法标识符</a>或者 Stripe <code v-pre>PaymentMethod</code> 对象后将开始订阅, 并使用客户 ID 和其他相关的账单信息更新数据库。</p>
<blockquote>
<p>注意：直接传递支付方法标识符到 <code v-pre>create()</code> 方法也可以将用户的付款方式储存到数据库。</p>
</blockquote>
<h4 id="用户其他的详细信息" tabindex="-1"><a class="header-anchor" href="#用户其他的详细信息"><span>用户其他的详细信息</span></a></h4>
<p>如果您想要指定用户其他的详细信息，您可以通过将它们作为第二个参数传递给 <code v-pre>create</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'monthly'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token variable">$email</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要了解更多关于 Stripe 支持的额外字段，请查看 Stripe 的<a href="https://stripe.com/docs/api#create_customer" target="_blank" rel="noopener noreferrer">内容创建客户文档</a>。</p>
<h4 id="优惠券" tabindex="-1"><a class="header-anchor" href="#优惠券"><span>优惠券</span></a></h4>
<p>如果您想在创建订阅时使用优惠券，您可以使用 <code v-pre>withCoupon</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'monthly'</span><span class="token punctuation">)</span></span>
<span class="line">     <span class="token operator">-></span><span class="token function">withCoupon</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'code'</span><span class="token punctuation">)</span></span>
<span class="line">     <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="检查订阅状态" tabindex="-1"><a class="header-anchor" href="#检查订阅状态"><span>检查订阅状态</span></a></h3>
<p>一旦用户在您的应用程序订阅了，您可以使用各种方便的方法轻松地检查他们的订阅状态。首先，如果用户有一个激活的订阅，那么 <code v-pre>subscribed</code> 的方法将返回 <code v-pre>true</code> ，即使订阅当前处于试用阶段：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscribed</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这个 <code v-pre>subscribed</code> 方法还可以在 <a href="https://learnku.com/docs/laravel/6.x/middleware" target="_blank" rel="noopener noreferrer">路由中间件</a>使用，允许您根据用户的订阅状态对路由和控制器进行访问：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Closure</span> <span class="token variable">$next</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">subscribed</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 该用户不是付费客户......</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果您想要确定用户是否仍然处于试用阶段，您可以使用 <code v-pre>onTrial</code> 方法。这个方法对于向用户显示他们仍然处于试用期的警告是很有用的：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>基于给定的 Stripe 计划 ID，可以使用 <code v-pre>subscribedToPlan</code> 方法来确定用户是否订阅了该计划。在本例中，我们将确定用户的 <code v-pre>main</code> 订阅是否激活了 <code v-pre>monthly</code> 计划：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscribedToPlan</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'monthly'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>recurring</code> 方法可用于确定用户当前是否已订阅，并且不再处于试用阶段：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">recurring</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="取消订阅状态" tabindex="-1"><a class="header-anchor" href="#取消订阅状态"><span>取消订阅状态</span></a></h4>
<p>为了确定用户是否曾经订阅，但是已经取消了他们的订阅，您可以使用 <code v-pre>cancelled</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancelled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>您还可以确定用户是否已经取消了订阅，但是仍然处于订阅的「宽限期」，直到订阅完全过期为止。例如，如果用户在 3 月 5 日取消了原定于 3 月 10 日到期的订阅，那么用户将在 3 月 10 日之前进行「宽限期」。请注意，在此期间 <code v-pre>subscribed</code> 方法仍然返回 <code v-pre>true</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果要确定用户取消订阅的时间是否已不在其「宽限期」 内，可以使用 <code v-pre>ended</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">ended</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="不完整和过期状态" tabindex="-1"><a class="header-anchor" href="#不完整和过期状态"><span>不完整和过期状态</span></a></h4>
<p>如果订阅需要在创建后进行二次付款操作，则订阅将被标记为 <code v-pre>incomplete</code> 。订阅状态存储在 <code v-pre>stripe_status</code> Cashier <code v-pre>subscriptions</code> 数据库表的列中。</p>
<p>同样，如果在交换计划时需要进行二次付款操作，则订阅将被标记为 <code v-pre>past_due</code> 。当您的订阅处于这两种状态时，在客户确认付款之前，它将不会处于活动状态。检查订阅是否有不完整的付款可以使用 <code v-pre>hasIncompletePayment</code> Billable模型或订阅实例上的方法完成：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">hasIncompletePayment</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">hasIncompletePayment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果订阅的付款不完整，您应该将用户定向到收银员的付款确认页面，并传递<code v-pre>latestPayment</code> 标识符。您可以使用 <code v-pre>latestPayment</code> 订阅实例上的可用方法来检索此标识符：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token operator">&lt;</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"{{ route('cashier.payment', <span class="token interpolation"><span class="token variable">$subscription</span><span class="token operator">-></span><span class="token property">latestPayment</span></span>()->id) }}"</span><span class="token operator">></span></span>
<span class="line">    Please confirm your payment<span class="token operator">.</span></span>
<span class="line"><span class="token operator">&lt;</span><span class="token operator">/</span>a<span class="token operator">></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>注意：订阅处于某种 <code v-pre>incomplete</code> 状态时，在确认付款之前无法更改。因此，当订阅处于某种状态时， <code v-pre>swap</code> 和 <code v-pre>updateQuantity</code> 方法将抛出异常 <code v-pre>incomplete</code> 。</p>
</blockquote>
<h3 id="修改订阅计划" tabindex="-1"><a class="header-anchor" href="#修改订阅计划"><span>修改订阅计划</span></a></h3>
<p>用户在您的应用程序中订阅了之后，他们可能会偶尔想要更改一个新的订阅计划。要将一个用户切换到一个新的订阅，需将订阅计划的标识符传递给 <code v-pre>swap</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context">App<span class="token punctuation">\</span>User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'provider-plan-id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果用户在试用期，试用期的期限会被保留。另外，如果订阅的数量存在「份额」，那么该份额也将保持。</p>
<p>如果你想在更改用户订阅计划的时候取消用户当前订阅的试用期，可以使用 <code v-pre>skipTrial</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">skipTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">-></span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'provider-plan-id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想在更改用户订阅计划的时候就为用户开具发票信息，而不是等待下一个结算周期, 你可以使用 <code v-pre>swapAndInvoice</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context">App<span class="token punctuation">\</span>User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">swapAndInvoice</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'provider-plan-id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="订阅量" tabindex="-1"><a class="header-anchor" href="#订阅量"><span>订阅量</span></a></h3>
<p>有些时候订阅是会受「数量」影响的。举个例子，你的应用程序的付费方式可能是<strong>每个账户</strong> $10 / 月。你可以使用 <code v-pre>incrementQuantity</code> 和 <code v-pre>decrementQuantity</code> 方法轻松地增加或减少你的订阅量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">incrementQuantity</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 对当前的订阅量加5...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">incrementQuantity</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">decrementQuantity</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 对当前的订阅量减5...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">decrementQuantity</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>或者，你可以使用 <code v-pre>updateQuantity</code> 方法设定一个特定的数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">updateQuantity</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>noProrate</code> 方法可用于更新订阅的数量，而不会对收费进行定价：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">noProrate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">updateQuantity</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要获得更多关于订阅量的信息，请参考 <a href="https://stripe.com/docs/subscriptions/quantities" target="_blank" rel="noopener noreferrer">Stripe 文档</a>.</p>
<h3 id="订阅税额" tabindex="-1"><a class="header-anchor" href="#订阅税额"><span>订阅税额</span></a></h3>
<p>在计费模式上实现 <code v-pre>taxPercentage</code> 方法，并且返回一个 0 到 100 不超过 2 位小数的数字，用来指定用户在订阅中支付的税率百分比。</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">taxPercentage</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token number">20</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>taxPercentage</code> 方法使你能够在模型的基础上应用税率，这对于一个跨越多个国家和税率的用户群可能有帮助。</p>
<blockquote>
<p>注意：<code v-pre>taxPercentage</code> 方法只适用于付费订阅模式。如果你用 charges 来做「一次性」收费，你需要同时手工指定税率。</p>
</blockquote>
<h4 id="同步税率百分比" tabindex="-1"><a class="header-anchor" href="#同步税率百分比"><span>同步税率百分比</span></a></h4>
<p>当更改 <code v-pre>taxPercentage</code> 方法返回的硬编码值时，用户的任何现有订阅的税率设置将保持不变。如果要用返回的 <code v-pre>taxPercentage</code> 值更新现有订阅的税率，应在用户的订阅实例上调用 <code v-pre>syncTaxPercentage</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">syncTaxPercentage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="订阅锚定日期" tabindex="-1"><a class="header-anchor" href="#订阅锚定日期"><span>订阅锚定日期</span></a></h3>
<p>默认情况下，计费周期锚定是创建订阅的日期，如果使用试用期，则是试用结束的日期。如果要修改账单锚定日期，可以使用 <code v-pre>anchorBillingCycleOn</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Carbon<span class="token punctuation">\</span>Carbon</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$anchor</span> <span class="token operator">=</span> <span class="token class-name static-context">Carbon</span><span class="token operator">::</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'first day of next month'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'premium'</span><span class="token punctuation">)</span></span>
<span class="line">            <span class="token operator">-></span><span class="token function">anchorBillingCycleOn</span><span class="token punctuation">(</span><span class="token variable">$anchor</span><span class="token operator">-></span><span class="token function">startOfDay</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span>
<span class="line">            <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>有关管理订阅计费周期的详细信息，请参阅 <a href="https://stripe.com/docs/billing/subscriptions/billing-cycle" target="_blank" rel="noopener noreferrer">Stripe 计划周期文档</a></p>
<h3 id="取消订阅" tabindex="-1"><a class="header-anchor" href="#取消订阅"><span>取消订阅</span></a></h3>
<p>在用户订阅上调用 <code v-pre>cancel</code> 方法用来取消订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>当一个订阅被取消时，Cashier 将会自动在你的数据库中设置 <code v-pre>ends_at</code> 列。这个列经常被用来获悉 <code v-pre>subscribed</code> 字段何时应该开始返回 <code v-pre>false</code> 。例如，如果客户在 3 月 1 日取消订阅，但是订阅计划直到 3 月 5 日才结束，<code v-pre>subscribed</code> 方法将会继续返回 <code v-pre>true</code> 一直到 3 月 5 日。</p>
<p>你可以使用 <code v-pre>onGracePeriod</code> 方法确定用户是否确定订阅，但是仍然存在一个「宽限期」：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onGracePeriod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想马上取消订阅，请在用户的订阅中调用 cancelNow 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cancelNow</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="恢复订阅" tabindex="-1"><a class="header-anchor" href="#恢复订阅"><span>恢复订阅</span></a></h3>
<p>如果一个用已经取消订阅，你可以在你希望恢复它的时候使用 resume 方法。用户 <strong>必须</strong> 仍然在他们的宽限期内才可以恢复订阅：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">resume</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>如果用户已取消订阅，然后在订阅宽限期前恢复该订阅，他们将不会被立即计费。相反，他们的订阅将会被重新激活，需要按照原来的支付流程再次进行支付。</p>
<h2 id="试用订阅" tabindex="-1"><a class="header-anchor" href="#试用订阅"><span>试用订阅</span></a></h2>
<h3 id="以信用卡订阅" tabindex="-1"><a class="header-anchor" href="#以信用卡订阅"><span>以信用卡订阅</span></a></h3>
<p>如果你想给你的顾客提供试用期，同时收集支付方法信息，那么你应该在创建订阅使用 <code v-pre>trialDays</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'monthly'</span><span class="token punctuation">)</span></span>
<span class="line">            <span class="token operator">-></span><span class="token function">trialDays</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span></span>
<span class="line">            <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>该方法会在数据库订阅记录上设置订阅期结束时间，以便告知 Sripe 在此之前不要计算用户的账单信息。当使用 <code v-pre>trialDays</code> 方法时，Cashier将覆盖 Stripe 中配置的所有默认试用期。</p>
<blockquote>
<p>注意：如果顾客没有在试用期结束前取消订阅，订阅会被自动结算，所以你应该确保告知你的用户他们的试用结束期。</p>
</blockquote>
<p><code v-pre>trialUntil</code> 方法允许提供 <code v-pre>DateTime</code> 实例指定试用结束期：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Carbon<span class="token punctuation">\</span>Carbon</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'monthly'</span><span class="token punctuation">)</span></span>
<span class="line">            <span class="token operator">-></span><span class="token function">trialUntil</span><span class="token punctuation">(</span><span class="token class-name static-context">Carbon</span><span class="token operator">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addDays</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span>
<span class="line">            <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用用户实例的 <code v-pre>onTrial</code> 方法或者订阅实例的 <code v-pre>onTrial</code> 方法判断用户是否处于试用期。下面两个示例等价：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">subscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="非信用卡订阅" tabindex="-1"><a class="header-anchor" href="#非信用卡订阅"><span>非信用卡订阅</span></a></h3>
<p>如果你不想在提供试用期的时候收集用户支付方式信息，只需设置用户记录的 <code v-pre>trial_ends_at</code> 列为期望的试用期结束日期即可，这通常在用户注册期间完成：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">// 填充其他用户属性……</span></span>
<span class="line">    <span class="token string single-quoted-string">'trial_ends_at'</span> <span class="token operator">=></span> <span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">addDays</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>注意：确保已添加 <code v-pre>trial_ends_at</code> <a href="https://learnku.com/docs/laravel/6.x/eloquent-mutators#date-mutators" target="_blank" rel="noopener noreferrer">日期修改器</a> 到模型定义。</p>
</blockquote>
<p>Cashier 把这种类型的引用称为「一般体验」，因为它没有关联任何已存在的订阅。如果当前的日期没有超过 <code v-pre>trail_ends_at</code> 值， <code v-pre>User</code> 实例的 <code v-pre>onTrial</code> 方法将会返回 <code v-pre>true</code> ：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户在他们的试用期内...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你希望明确的知道用户处于「一般」试用期，并且还未创建实际的订阅，那么你可以使用 <code v-pre>onGenericTrial</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">onGenericTrial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户在他们「一般」试用期...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你准备给用户创建实际的订阅，通常你可以使用 <code v-pre>newSubsription</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'main'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'monthly'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="处理-stripe-webhooks" tabindex="-1"><a class="header-anchor" href="#处理-stripe-webhooks"><span>处理 Stripe Webhooks</span></a></h2>
<blockquote>
<p>提示：你可以使用 <a href="https://learnku.com/docs/laravel/6.x/valet" target="_blank" rel="noopener noreferrer">Laravel Valet's</a>中的 <code v-pre>valet share</code> 命令来帮助你在本地开发期间测试webhook。</p>
</blockquote>
<p>Stripe可以通过webhooks通知应用各种各样的事件。 默认情况下，需要定义一个 Cashier 的 webhook 控制器的路由。这个控制器用来处理所有传入的webhook请求。</p>
<p>默认情况下，这个控制器将会自动对支付失败次数过多（这个次数可以在 Stripe 设置中定义）的订阅进行取消；此外，我们很快会发现，你可以扩展这个控制器去处理任何你想要处理的 webhook 事件。</p>
<p>为了确保您的应用可以处理Stripe webhook，请务必在Stripe控制面板中配置webhook URL。Stripe 控制面板中应该配置的所有webhook完整列表如下：</p>
<ul>
<li><code v-pre>customer.subscription.updated</code></li>
<li><code v-pre>customer.subscription.deleted</code></li>
<li><code v-pre>customer.updated</code></li>
<li><code v-pre>customer.deleted</code></li>
<li><code v-pre>invoice.payment_action_required</code></li>
</ul>
<blockquote>
<p>注意：请确保使用 Cashier 的 <a href="https://learnku.com/docs/laravel/6.x/billing#verifying-webhook-signatures" target="_blank" rel="noopener noreferrer">webhook 验签</a> 中间件来保护传入请求。</p>
</blockquote>
<h4 id="webhooks-csrf-保护" tabindex="-1"><a class="header-anchor" href="#webhooks-csrf-保护"><span>Webhooks &amp; CSRF 保护</span></a></h4>
<p>因为 Stripe webhooks 需要绕过 Laraval 的 <a href="https://learnku.com/docs/laravel/6.x/csrf" target="_blank" rel="noopener noreferrer">CSRF 保护</a>, 请确保在您的 <code v-pre>VerifyCsrfToken</code> 中间件含有 URI ，或者将其置于 <code v-pre>web</code> 中间件组之外：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">protected</span> <span class="token variable">$except</span> <span class="token operator">=</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'stripe/*'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="定义-webhook-事件处理程序" tabindex="-1"><a class="header-anchor" href="#定义-webhook-事件处理程序"><span>定义 Webhook 事件处理程序</span></a></h3>
<p>Cashier 对于失败支付自动进行取消订阅，但是如果您有其他的 Stripe Webhook 事件希望去处理，可以扩展 Webhook 控制器。您的方法名应该与 Cashier 期望的约定相符，更具体的说，您希望处理 Stripe webhook 的方法应该以 <code v-pre>handle</code> 和 「驼峰」 名为前缀。举例来说，如果您希望处理 <code v-pre>invoice.payment_succeeded</code> 的 webhook，您应该在控制器添加<code v-pre>handleInvoicePaymentSucceeded</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>WebhookController</span> <span class="token keyword">as</span> CashierController<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">WebhookController</span> <span class="token keyword">extends</span> <span class="token class-name">CashierController</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * Handle invoice payment succeeded.</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token keyword">array</span></span>  <span class="token parameter">$payload</span></span>
<span class="line">     * <span class="token keyword">@return</span> <span class="token class-name"><span class="token punctuation">\</span>Symfony<span class="token punctuation">\</span>Component<span class="token punctuation">\</span>HttpFoundation<span class="token punctuation">\</span>Response</span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handleInvoicePaymentSucceeded</span><span class="token punctuation">(</span><span class="token variable">$payload</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// 此处处理事件</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>接下来，在 <code v-pre>routes/web.php</code> 文件中定义 Cashier 控制器的路由, 这将会覆盖掉默认的路由:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span></span>
<span class="line">    <span class="token string single-quoted-string">'stripe/webhook'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'\App\Http\Controllers\WebhookController@handleWebhook'</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="订阅失败" tabindex="-1"><a class="header-anchor" href="#订阅失败"><span>订阅失败</span></a></h3>
<p>如果用户的信用卡过期怎么办？不用担心 - Cashier 包含了一个 Webhook 控制器可以轻松为您取消用户的订阅。 该控制器会在 Stripe 判断订阅失败后（通常尝试支付失败 3 次及以上）取消用户的订阅。</p>
<h3 id="webhook-验签" tabindex="-1"><a class="header-anchor" href="#webhook-验签"><span>Webhook 验签</span></a></h3>
<p>为了保护 Webhook，您需要使用 <a href="https://stripe.com/docs/webhooks/signatures" target="_blank" rel="noopener noreferrer">Stripe 的 Webhook 签名</a>。为了方便，Cashier 包含一个中间件，用于验证传入 Stripe webhook 的请求是否有效。</p>
<p>如果要启用 Webhook 验证，请确保在 <code v-pre>.env</code> 配置文件中设置了 <code v-pre>STRIPE_WEBHOOK_SECRET</code> 的值。 Webhook的 <code v-pre>secret</code> 可以从 Stripe 用户控制面板中找到。</p>
<h2 id="一次性支付" tabindex="-1"><a class="header-anchor" href="#一次性支付"><span>一次性支付</span></a></h2>
<h3 id="简单支付" tabindex="-1"><a class="header-anchor" href="#简单支付"><span>简单支付</span></a></h3>
<blockquote>
<p>注意： <code v-pre>charge</code> 方法接收您想支付于 <strong>应用程序使用的货币的最小单位 的金额</strong>。</p>
</blockquote>
<p>如果您想对订阅客户的信用卡收取「一次性」费用，可以在可计费模型实例上使用 <code v-pre>charge</code> 方法。 您需要将 <a href="#storing-payment-methods">支付方式识别码</a> 作为第二个参数:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// Stripe 接收分为单位的费用...</span></span>
<span class="line"><span class="token variable">$stripeCharge</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>charge</code> 方法接受一个数组作为它的第三个参数, 允许您创建支付时将任何您想要的选项传递给底层的 Stripe。有关在创建支付时可用的选项，请参阅 Stripe 文档：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token variable">$paymentMethod</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'custom_option'</span> <span class="token operator">=></span> <span class="token variable">$value</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果支付失败， <code v-pre>charge</code> 方法将会抛出异常。如果支付成功，一个 <code v-pre>Laravel\Cashier\Payment</code> 实例会从该方法返回：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">try</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$payment</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> <span class="token variable">$e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="发票" tabindex="-1"><a class="header-anchor" href="#发票"><span>发票</span></a></h3>
<p>有时您可能需要支付一次性费用同时也需要生成费用发票，以便可以向客户提供 PDF 文件格式的收据。 <code v-pre>invoiceFor</code> 方法可以让您做到这一点。 例如，向客户开具 5.00 美元的「一次性费用」发票：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// Stripe 接收分为单位的费用...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">invoiceFor</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'One Time Fee'</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div></div></div><p>账单会立刻向用户的默认支付方式收取费用。 <code v-pre>invoiceFor</code> 方法接收一个数组作为第三个参数，这个数组包含了所购内容的账单选项。接收的第四个参数也是一个数组， 这最后一个参数包含了发票自身的一些选项：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">invoiceFor</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Stickers'</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'quantity'</span> <span class="token operator">=></span> <span class="token number">50</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'tax_percent'</span> <span class="token operator">=></span> <span class="token number">21</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>注意： <code v-pre>invoiceFor</code> 方法将会创建 Stripe 发票，该发票将会在支付失败后重试。如果您不想失败后重试，您需要在第一次支付失败后调用 Stripe API 关闭它。</p>
</blockquote>
<h3 id="关于退款" tabindex="-1"><a class="header-anchor" href="#关于退款"><span>关于退款</span></a></h3>
<p>如果您需要处理退款，您可以使用 <code v-pre>refund</code> 方法。此方法接受 Stripe Payment Intent ID 作为其第一个参数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$payment</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">charge</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">refund</span><span class="token punctuation">(</span><span class="token variable">$payment</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="发票-1" tabindex="-1"><a class="header-anchor" href="#发票-1"><span>发票</span></a></h2>
<p>您可以使用 <code v-pre>invoices</code> 方法轻松获取账单模型的发票数组：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$invoices</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">invoices</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 结果包含处理中的发票...</span></span>
<span class="line"><span class="token variable">$invoices</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">invoicesIncludingPending</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当列出客户发票清单时，可以使用发票辅助函数来显示相关的发票信息。例如，您可能希望在表格中列出每张发票，从而方便客户下载它们：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token operator">&lt;</span>table<span class="token operator">></span></span>
<span class="line">    @<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$invoices</span> <span class="token keyword">as</span> <span class="token variable">$invoice</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">&lt;</span>tr<span class="token operator">></span></span>
<span class="line">            <span class="token operator">&lt;</span>td<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$invoice</span><span class="token operator">-></span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">toFormattedDateString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>td<span class="token operator">></span></span>
<span class="line">            <span class="token operator">&lt;</span>td<span class="token operator">></span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">$invoice</span><span class="token operator">-></span><span class="token function">total</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>td<span class="token operator">></span></span>
<span class="line">            <span class="token operator">&lt;</span>td<span class="token operator">></span><span class="token operator">&lt;</span>a href<span class="token operator">=</span><span class="token string double-quoted-string">"/user/invoice/{{ <span class="token interpolation"><span class="token variable">$invoice</span><span class="token operator">-></span><span class="token property">id</span></span> }}"</span><span class="token operator">></span>Download<span class="token operator">&lt;</span><span class="token operator">/</span>a<span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>td<span class="token operator">></span></span>
<span class="line">        <span class="token operator">&lt;</span><span class="token operator">/</span>tr<span class="token operator">></span></span>
<span class="line">    @<span class="token keyword">endforeach</span></span>
<span class="line"><span class="token operator">&lt;</span><span class="token operator">/</span>table<span class="token operator">></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="生成-pdf-发票" tabindex="-1"><a class="header-anchor" href="#生成-pdf-发票"><span>生成 PDF 发票</span></a></h3>
<p>在路由或控制器中，使用 <code v-pre>downloadInvoice</code> 方法生成一个发票的 PDF 下载。这个方法会自动给浏览器生成合适的 HTTP 下载响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'user/invoice/{invoice}'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token variable">$invoiceId</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">downloadInvoice</span><span class="token punctuation">(</span><span class="token variable">$invoiceId</span><span class="token punctuation">,</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'vendor'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Your Company'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'product'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Your Product'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="strong-customer-authentication" tabindex="-1"><a class="header-anchor" href="#strong-customer-authentication"><span>Strong Customer Authentication</span></a></h2>
<p>如果您的业务立足于欧洲，那么您就需要遵守 Strong Customer Authentication (SCA) 法规。这些法规由欧盟发布于 2019 年 9 月，意在预防支付欺诈。 幸运的是， Stripe 与 Cashier 已经准备好构建符合 SCA 的应用。</p>
<blockquote>
<p>注意：在您开始之前， 请先阅读 <a href="https://stripe.com/en-be/guides/strong-customer-authentication" target="_blank" rel="noopener noreferrer">Stripe's guide on PSD2 and SCA</a> 与 <a href="https://stripe.com/docs/strong-customer-authentication" target="_blank" rel="noopener noreferrer">新 SCA API 文档</a>.</p>
</blockquote>
<h3 id="需要额外验证的支付" tabindex="-1"><a class="header-anchor" href="#需要额外验证的支付"><span>需要额外验证的支付</span></a></h3>
<p>SCA 通常在处理支付时需要额外的验证步骤。当这种情况出现时， Cashier 会抛出 <code v-pre>IncompletePayment</code> 来提示您需要额外的验证步骤。 当异常抛出时，您有两个选择。</p>
<p>您可以引导用户跳转到 Cashier 自带的支付确认页面完成验证。这个页面已经关联由 Cashier 的服务提供者注册的路由。因此，您可以捕获 <code v-pre>IncompletePayment</code> 后跳转到支付确认界面：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Cashier<span class="token punctuation">\</span>Exceptions<span class="token punctuation">\</span>IncompletePayment</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">try</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$subscription</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">newSubscription</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'default'</span><span class="token punctuation">,</span> <span class="token variable">$planId</span><span class="token punctuation">)</span></span>
<span class="line">                            <span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token variable">$paymentMethod</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IncompletePayment</span> <span class="token variable">$exception</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">route</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token string single-quoted-string">'cashier.payment'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">[</span><span class="token variable">$exception</span><span class="token operator">-></span><span class="token property">payment</span><span class="token operator">-></span><span class="token property">id</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'redirect'</span> <span class="token operator">=></span> <span class="token function">route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">]</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在支付确认界面，用户则需要再次输入他们的信用卡信息以及进行任何 Stripe 要求的操作。例如输入信用卡的“3D安全信息”来确认支付。当他们完成确认后，用户会被重定向到上方 <code v-pre>redirect</code> 定义的URL。</p>
<p>或者，您可以让 Stripe 来为您处理此次支付确认。在这种情况下，您可以在 Stripe 仪表板设置 <a href="https://dashboard.stripe.com/account/billing/automatic" target="_blank" rel="noopener noreferrer">自动账单邮箱</a> 。如果捕获到<code v-pre>IncompletePayment</code>，您还是要告知用户他们会在邮箱内收到处理支付的引导邮件。</p>
<p><code v-pre>IncompletePayment</code> 异常会由以下方法抛出：<br>
<code v-pre>charge</code>, <code v-pre>invoiceFor</code>, 和在 <code v-pre>Billable</code>（可收费）用户的 <code v-pre>invoice</code> 方法。 当处理订阅时， 在 <code v-pre>IncompletePayment</code> 中的 <code v-pre>create</code>方法，与在 <code v-pre>IncompletePayment</code> 中的 <code v-pre>incrementAndInvoice</code> 和 <code v-pre>swapAndInvoice</code> 会抛出异常。</p>
<h4 id="账单未完成与已逾期" tabindex="-1"><a class="header-anchor" href="#账单未完成与已逾期"><span>账单未完成与已逾期</span></a></h4>
<p>每当账单需要额外确认时，订阅在数据库中的 <code v-pre>stripe_status</code> 列留下 <code v-pre>incomplete</code> 或 <code v-pre>past_due</code> 状态。当 Webhook 确认支付已完成时，Cashier 会立即激活用户的订阅。</p>
<p>如果您要了解更多关于 <code v-pre>incomplete</code> 与 <code v-pre>past_due</code> 状态的信息，请参考<a href="#incomplete-and-past-due-status">额外文档</a>.</p>
<h3 id="非会话支付通知" tabindex="-1"><a class="header-anchor" href="#非会话支付通知"><span>非会话支付通知</span></a></h3>
<p>尽管用户订阅已经激活，但 SCA 要求用户时不时验证其支付信息。 Cashier 可以发送一封邮件提醒用户需要非会话支付通知。例如，当用户订阅需要续费时， Cashier 的支付通知可以在环境变量中将 <code v-pre>CASHIER_PAYMENT_NOTIFICATION</code> 分配给一个类来启用。这默认是禁用的。当然，如果您不想使用 Cashier 提供的这个通知类，您可以使用自己的类来完成：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token constant">CASHIER_PAYMENT_NOTIFICATION</span><span class="token operator">=</span>Laravel\Cashier\Notifications\ConfirmPayment</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>为了确保非会话支付通知送达， 您需要确认已经在 Stripe 仪表盘完成 <a href="#handling-stripe-webhooks">Stripe Webhook 配置</a>和已启用<code v-pre>invoice.payment_action_required</code> Webhook。 您的 <code v-pre>Billable</code> 模型应使用 Laravel 的 <code v-pre>Illuminate\Notifications\Notifiable</code> trait。</p>
<blockquote>
<p>注意：当用户手动支付了一个需要额外确认的订单时，通知仍然会被发送。不幸的是，Stripe 无法确认用户是手动支付的还是使用非会话（Off-Session）方式支付。但是，用户确认支付以后返回支付页面，他们可以看见一个简单的 “支付成功” 提示。这样用户就无法再意外情况下再次确认支付，导致二次付费的情况发生。</p>
</blockquote>
<blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/6.x/billing/5187" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/6.x/bil...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/6.x/billing/5187" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/6.x/bil...</a></p>
</blockquote>
</div></template>


